﻿
using System;
using System.Collections.Generic;
using System.Linq;


namespace Boilen.Primitives {

    /// <summary>
    /// Ensures arguments are valid.
    /// </summary>
    static class Ensure {

        /// <summary>
        /// Ensures arguments are not null.
        /// </summary>
        /// <param name="args">The argument values to check.</param>
        public static void NotNull( params object[] args ) {
            if( args == null ) { throw new ArgumentNullException( "args" ); }
            if( args.Length == 0 ) { throw new ArgumentException( "args" ); }

            for( int i = 0; i < args.Length; ++i )
                if( args[i] == null )
                    throw new ArgumentNullException( "args[" + i + "]" );
        }

        /// <summary>
        /// Ensures string argument is not null or empty.
        /// </summary>
        /// <param name="value">The string value to check.</param>
        public static void NotNullOrEmpty( string value ) {
            Ensure.NotNull( value );
            if( value.Length == 0 )
                throw new ArgumentException( "String cannot be empty." );
        }

        /// <summary>
        /// Ensures collection argument is not null or empty.
        /// </summary>
        /// <param name="collection">The collection to check.</param>
        public static void NotNullOrEmpty<T>( IEnumerable<T> collection ) {
            Ensure.NotNull( collection );
            if( !collection.Any( ) )
                throw new ArgumentException( "Collection cannot be empty." );
        }

        /// <summary>
        /// Ensures the argument satisfies the specified condition.
        /// </summary>
        /// <param name="condition">The condition to check.</param>
        /// <param name="argumentName">The name of the argument.</param>
        /// <param name="message">The error message to use if the <paramref name="condition"/> is <false/>.</param>
        /// <param name="args">The format arguments for <paramref name="message"/>.</param>
        public static void ArgSatisfies( bool condition, string argumentName, string message, params object[] args ) {
            if( !condition )
                throw new ArgumentException( string.Format( message, args ), argumentName );
        }

        /// <summary>
        /// Ensures the argument satisfies the specified condition.
        /// </summary>
        /// <typeparam name="T">The actual type of the implementer.</typeparam>
        /// <param name="propertyType">The type of the dependency property given to the implementer.</param>
        public static void ArgTypeMatches<T>( Type propertyType ) {
            var aliasType = Util.GetAttribute<AliasTypeAttribute>( typeof( T ) );
            Type expectedType = aliasType == null ? typeof( T ) : aliasType.Alias;
            Ensure.ArgSatisfies( propertyType == expectedType, "T", "Property type {0} does not match implementer type argument {1}.", propertyType, typeof( T ) );
        }


        /// <summary>
        /// Ensures the specified condition is satisfied.
        /// </summary>
        /// <param name="condition">The condition to check.</param>
        /// <param name="message">The error message to use if the <paramref name="condition"/> is <false/>.</param>
        /// <param name="args">The format arguments for <paramref name="message"/>.</param>
        public static void Satisfies( bool condition, string message, params object[] args ) {
            if( !condition )
                throw new InvalidOperationException( string.Format( message, args ) );
        }

    }

}
